fix: handle SIGPIPE in Fetch PR changed files step to prevent missing delimiter error#1651
Conversation
… delimiter error When the PR diff exceeds 8000 bytes, `gh api ... | head -c 8000` causes SIGPIPE (exit 141) on the gh api process. GitHub Actions bash uses `-eo pipefail`, so the pipeline failure aborts the subshell before writing the closing heredoc delimiter to GITHUB_OUTPUT, resulting in: ##[error]Invalid value. Matching delimiter not found 'GHAW_PR_FILES_...' Fix: add `|| true` after `head -c 8000` to swallow the SIGPIPE/pipefail error, ensuring the closing delimiter is always written to GITHUB_OUTPUT. Fixes failing job: https://github.com/github/gh-aw-firewall/actions/runs/23964770751/job/69902358339 Agent-Logs-Url: https://github.com/github/gh-aw-firewall/sessions/c8b8f958-f52e-4390-af7d-f094e20e68da Co-authored-by: lpcox <15877973+lpcox@users.noreply.github.com>
There was a problem hiding this comment.
Pull request overview
This PR updates the Security Guard workflow’s “Fetch PR changed files” step to avoid a GitHub Actions GITHUB_OUTPUT delimiter error caused by bash -eo pipefail aborting on SIGPIPE when truncating large PR diffs.
Changes:
- Swallow the pipeline failure from
gh api ... | head -c 8000by appending|| trueso the closing delimiter is always written. - Apply the same change to both the source workflow (
.md) and the compiled workflow (.lock.yml).
Show a summary per file
| File | Description |
|---|---|
| .github/workflows/security-guard.md | Adds ` |
| .github/workflows/security-guard.lock.yml | Mirrors the same ` |
Copilot's findings
Tip
Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
- Files reviewed: 2/2 changed files
- Comments generated: 2
| gh api "repos/${GH_REPO}/pulls/${PR_NUMBER}/files" \ | ||
| --paginate --jq '.[] | "### " + .filename + " (+" + (.additions|tostring) + "/-" + (.deletions|tostring) + ")\n" + (.patch // "") + "\n"' \ | ||
| | head -c 8000 | ||
| | head -c 8000 || true | ||
| echo "${DELIM}" |
There was a problem hiding this comment.
| head -c 8000 || true prevents the delimiter-missing failure, but it also suppresses all non-zero exits from the pipeline (e.g., gh api auth/permission/rate-limit failures), which can cause the workflow to proceed with an empty/incomplete PR_FILES output and silently degrade the security review.
Consider handling only the expected SIGPIPE/pipefail case (exit 141) while still closing the delimiter, and re-failing the step for any other error (e.g., by temporarily disabling errexit around the pipeline, capturing the pipeline/PIPESTATUS exit code, then deciding whether to ignore or exit).
See below for a potential fix:
pipeline_status=0
pipe_status=()
{
echo "PR_FILES<<${DELIM}"
set +e
gh api "repos/${GH_REPO}/pulls/${PR_NUMBER}/files" \
--paginate --jq '.[] | "### " + .filename + " (+" + (.additions|tostring) + "/-" + (.deletions|tostring) + ")\n" + (.patch // "") + "\n"' \
| head -c 8000
pipeline_status=$?
pipe_status=("${PIPESTATUS[@]}")
set -e
echo "${DELIM}"
} >> "$GITHUB_OUTPUT"
if [ "$pipeline_status" -ne 0 ]; then
if [ "${#pipe_status[@]}" -eq 2 ] && [ "${pipe_status[0]}" -eq 141 ] && [ "${pipe_status[1]}" -eq 0 ]; then
:
else
exit "$pipeline_status"
fi
fi
| run: "DELIM=\"GHAW_PR_FILES_$(date +%s)\"\n{\n echo \"PR_FILES<<${DELIM}\"\n gh api \"repos/${GH_REPO}/pulls/${PR_NUMBER}/files\" \\\n --paginate --jq '.[] | \"### \" + .filename + \" (+\" + (.additions|tostring) + \"/-\" + (.deletions|tostring) + \")\\n\" + (.patch // \"\") + \"\\n\"' \\\n | head -c 8000 || true\n echo \"${DELIM}\"\n} >> \"$GITHUB_OUTPUT\"\n" | ||
|
|
There was a problem hiding this comment.
The added || true fixes the missing-delimiter error, but it also masks genuine gh api failures (auth/permission/rate-limit/network), letting the job continue with an empty/truncated PR_FILES output.
Recommend adjusting the script to ignore only the expected SIGPIPE/pipefail exit (141) while still emitting the closing delimiter, and to fail the step for other non-zero statuses.
| run: "DELIM=\"GHAW_PR_FILES_$(date +%s)\"\n{\n echo \"PR_FILES<<${DELIM}\"\n gh api \"repos/${GH_REPO}/pulls/${PR_NUMBER}/files\" \\\n --paginate --jq '.[] | \"### \" + .filename + \" (+\" + (.additions|tostring) + \"/-\" + (.deletions|tostring) + \")\\n\" + (.patch // \"\") + \"\\n\"' \\\n | head -c 8000 || true\n echo \"${DELIM}\"\n} >> \"$GITHUB_OUTPUT\"\n" | |
| run: | | |
| DELIM="GHAW_PR_FILES_$(date +%s)" | |
| { | |
| echo "PR_FILES<<${DELIM}" | |
| set +e | |
| gh api "repos/${GH_REPO}/pulls/${PR_NUMBER}/files" \ | |
| --paginate --jq '.[] | "### " + .filename + " (+" + (.additions|tostring) + "/-" + (.deletions|tostring) + ")\n" + (.patch // "") + "\n"' \ | |
| | head -c 8000 | |
| status=$? | |
| set -e | |
| echo "${DELIM}" | |
| } >> "$GITHUB_OUTPUT" | |
| if [ "$status" -ne 0 ] && [ "$status" -ne 141 ]; then | |
| exit "$status" | |
| fi |
* perf: optimize security-guard token usage - Restrict GitHub toolsets from [default] (52 tools) to [pull_requests, repos] (only tools actually used) - Add pre-compute step to fetch PR diff before agent starts, reducing tool calls needed for initial PR analysis - Add max-turns: 15 to prevent runaway token consumption - Add explicit network: allowed: [github] to restrict egress - Update prompt to reference pre-fetched diff data Closes #1647 Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> * fix: address review feedback on pre-compute step - Fix GITHUB_OUTPUT redirect: wrap gh api + delimiters in block redirect so output actually reaches the step output variable - Add if: guard for workflow_dispatch where PR number is absent - Network groups: kept as github-only since compiler auto-adds Claude API domains; api-proxy is not a standard network group Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> * fix: use jq string concatenation to avoid YAML escaping issue The jq string interpolation with escaped quotes (\"") gets double-escaped by the gh-aw compiler's YAML quoting, producing invalid jq at runtime. Switch to string concatenation (+) which avoids nested quotes entirely. Also simplifies the binary fallback from '"(binary)"' to '""' since binary files with no patch data aren't useful for review. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> * fix: use unique heredoc delimiter to avoid EOF collision The PR diff content can contain literal 'EOF' strings (e.g., from heredoc usage in shell scripts), which prematurely closes the GITHUB_OUTPUT delimiter. Use a timestamp-based unique delimiter (GHAW_PR_FILES_<epoch>) that won't collide with diff content. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> * fix: handle SIGPIPE in Fetch PR changed files step to prevent missing delimiter error (#1651) When the PR diff exceeds 8000 bytes, `gh api ... | head -c 8000` causes SIGPIPE (exit 141) on the gh api process. GitHub Actions bash uses `-eo pipefail`, so the pipeline failure aborts the subshell before writing the closing heredoc delimiter to GITHUB_OUTPUT, resulting in: ##[error]Invalid value. Matching delimiter not found 'GHAW_PR_FILES_...' Fix: add `|| true` after `head -c 8000` to swallow the SIGPIPE/pipefail error, ensuring the closing delimiter is always written to GITHUB_OUTPUT. Fixes failing job: https://github.com/github/gh-aw-firewall/actions/runs/23964770751/job/69902358339 Agent-Logs-Url: https://github.com/github/gh-aw-firewall/sessions/c8b8f958-f52e-4390-af7d-f094e20e68da Co-authored-by: copilot-swe-agent[bot] <198982749+Copilot@users.noreply.github.com> Co-authored-by: lpcox <15877973+lpcox@users.noreply.github.com> * fix: recompile security-guard.lock.yml to fix frontmatter hash mismatch (#1652) Agent-Logs-Url: https://github.com/github/gh-aw-firewall/sessions/0e4673e6-6f23-4e2d-8cc7-ccb922b81091 Co-authored-by: copilot-swe-agent[bot] <198982749+Copilot@users.noreply.github.com> Co-authored-by: lpcox <15877973+lpcox@users.noreply.github.com> * fix: ensure newline before heredoc closing delimiter head -c 8000 can truncate mid-line, leaving no trailing newline. The closing delimiter then appears on the same line as content and GitHub Actions fails to recognize it. Add an explicit echo to guarantee the delimiter is on its own line. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> * fix: increase smoke-claude max-turns and fix playwright log dir permissions (#1653) Root cause: Claude exceeded max-turns (9 > 8) because mcp__playwright__browser_navigate failed 3 times with EACCES on /tmp/gh-aw/mcp-logs/playwright/*.yml, consuming extra turns. Fixes: 1. Add pre-step to create /tmp/gh-aw/mcp-logs/playwright with chmod 777 before MCP Gateway starts - this ensures the playwright container can write page snapshot YAML files 2. Increase max-turns from 8 to 12 to handle transient playwright retries more robustly Recompile smoke-claude.lock.yml and run post-processing scripts. Agent-Logs-Url: https://github.com/github/gh-aw-firewall/sessions/7c6a8e3c-9a33-488d-a2a7-d54bdaed44a2 Co-authored-by: copilot-swe-agent[bot] <198982749+Copilot@users.noreply.github.com> Co-authored-by: lpcox <15877973+lpcox@users.noreply.github.com> --------- Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> Co-authored-by: Copilot <198982749+Copilot@users.noreply.github.com> Co-authored-by: lpcox <15877973+lpcox@users.noreply.github.com>
Root Cause
When the Security Guard workflow ran on PR #1648 (
perf/security-guard-token-optimization), the "Fetch PR changed files" step failed with:Why it failed: GitHub Actions' default
bashshell runs with-eo pipefail. Whengh api ... | head -c 8000executes and the PR diff exceeds 8000 bytes:head -c 8000reads exactly 8000 bytes and exits cleanly (exit 0)gh apireceives SIGPIPE (exit code 141) when it tries to write more datapipefail, the pipeline's exit code is 141 (non-zero)errexit, the subshell aborts before writing the closing delimiterecho "${DELIM}"PR_FILES<<GHAW_PR_FILES_...but no closing delimiter → errorFix
Added
|| trueafterhead -c 8000to swallow the SIGPIPE/pipefail error, ensuring the subshell always reachesecho "${DELIM}":Changes
.github/workflows/security-guard.md— source workflow file.github/workflows/security-guard.lock.yml— compiled workflow fileFixes failing job: https://github.com/github/gh-aw-firewall/actions/runs/23964770751/job/69902358339